package dpss.node;

import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Properties;

import dpss.commons.CustomLogger;
import dpss.commons.UDPMessage;
import dpss.commons.Util;
import dpss.node.server.Server;
import dpss.node.udp.UDPListener;

/**
 * The main Node manager
 * 
 * @author musab.mirza
 * 
 */
public class NodeManager implements Runnable{

	private static CustomLogger logger = CustomLogger.getInstance();
	private DatagramSocket socket;
	private InetSocketAddress replicaManagerSocketAddress;
	private static Properties prop;
	private Server server;

	/**
	 * Starter
	 * 
	 * @param args
	 */
	public static void main(String[] args) {
		new NodeManager(null);
	}

	public void run(){
		
	}
	
	/**
	 * Constructor
	 * 
	 * @throws SocketException
	 */
	public NodeManager(Properties properties) {

		logger.logConsole(true);
		
		// Load properties
		loadProperties(properties);
		
		// Create socket for sending
		createSocket();
		
		// Print header
		Util.printProgramName("Server node ["
				+ replicaManagerSocketAddress.toString() + "]");
		
		// Create server
		server = new Server(socket, replicaManagerSocketAddress);
		
		// Try to register server on the replica manager
		registerWithReplicaManager();
		
		// Start listening on the port
		new UDPListener(socket, server, replicaManagerSocketAddress).start();

	}

	/**
	 * Creates a UDP socket on the specified port
	 */
	private void createSocket() {
		try {
			socket = new DatagramSocket(Integer.parseInt((String) prop
					.get("self.port")));
		} catch (NumberFormatException | SocketException e1) {
			e1.printStackTrace();
			System.exit(0);
		}
	}

	/**
	 * Loads the properties from the propteries file
	 * @param properties 
	 */
	private void loadProperties(Properties constructorProps) {
		try {
			if (constructorProps == null)
				prop = Util.loadProperties("project.properties");
			else
				prop = constructorProps;
			InetAddress rmIp = InetAddress.getByName((String) prop
					.get("replicamanager.ip"));
			Integer rmPort = Integer.parseInt((String) prop
					.get("replicamanager.port"));
			replicaManagerSocketAddress = new InetSocketAddress(rmIp, rmPort);
		} catch (UnknownHostException e) {
			logger.log("ERROR - Could not connect to replica manager");
		}
	}

	/**
	 * Tries to register with the replica manager
	 */
	private void registerWithReplicaManager() {
		
		logger.log("Trying to register with Replica Manager");
		
		UDPMessage toSend = new UDPMessage("registerServerNode", null, true, "");
		UDPMessage.sendMessage(socket, toSend, replicaManagerSocketAddress);
		
		UDPMessage messageReceived = UDPMessage.receiveUDPMessage(socket);

		if (messageReceived.isSuccess()) {
			logger.log("Registered to the replica manager successfully, now waiting for initialization");;
		} else {
			logger.log("ERROR - Could not register with replica manager. Exiting.");
			System.exit(0);
		}
	}


}
